package com.he.filter;

import com.alibaba.fastjson2.JSON;
import com.he.constant.CommonConstant;
import com.he.constant.RedisConstant;
import com.he.domain.Result;
import com.he.entity.LoginUser;
import com.he.enums.LoginStatusEnum;
import com.he.interceptor.AccessLimitInterceptor;
import com.he.service.RedisService;
import com.he.utils.WebUtils;
import io.jsonwebtoken.Claims;
import com.he.utils.JwtUtil;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author He
 * @version 1.0
 * @Date 2023/9/6 23:18
 * @Desc JWT 认证的自定义过滤器 基于Token的身份验证 OncePerRequestFilter 保证在一次请求只通过一次filter，而不需要重复执行
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Resource
    private RedisService redisService;

    @Resource
    private AccessLimitInterceptor accessLimitInterceptor;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        System.out.println(request.getRequestURI());
        // 获取请求头中的token
        String token = request.getHeader("token");
        //没有token直接放行后面还有拦截器
        if(!StringUtils.hasText(token)){
            filterChain.doFilter(request, response);
            return;
        }
        // 解析userId
        Claims claims = null;
        try {
            claims = JwtUtil.parseJWT(token);
        } //token超时需要重新登录
        catch (ExpiredJwtException e) {
            e.printStackTrace();
            WebUtils.renderString(response, JSON.toJSONString(Result.fail(LoginStatusEnum.ACCOUNT_EXPIRED)));
            return;
        } //token非法需要重新登录
        catch(JwtException e){
            e.printStackTrace();
            WebUtils.renderString(response, JSON.toJSONString(Result.fail(LoginStatusEnum.TOKEN_INVALID)));
            return;
        }catch (Exception e){
            e.printStackTrace();
            return;
        }
        //我们登录成功存入的时userId所以这里是userId
        String userId = claims.getSubject();
        //从redis中获取用户信息
        LoginUser loginUser = redisService.getObject(RedisConstant.LOGIN_USER_KEY_PREFIX + userId);
        //如果Redis中获取不到也算过期
        if (Objects.isNull(loginUser)){
            //提示重新登录
            Result<?> result = Result.fail(LoginStatusEnum.ACCOUNT_EXPIRED);
            WebUtils.renderString(response, JSON.toJSONString(result));
            return;
        }
        //设置登录过期时间
        redisService.setObject(RedisConstant.LOGIN_USER_KEY_PREFIX + userId, loginUser, CommonConstant.SESSION_EXPIRE_TIME, TimeUnit.MINUTES);
        //存入SecurityContextHolder
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null,null);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        filterChain.doFilter(request, response);
    }
}

